package com.ics.atable.chat.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.ics.atable.chat.service.MetricAliasService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.ics.atable.chat.config.Nl2sqlConfiguration.OUTPUT;
import static com.ics.atable.chat.config.Nl2sqlConfiguration.REPLACE;

@Slf4j
@Component
@RequiredArgsConstructor
public class SqlMetricNormalizeNode implements NodeAction {

    private final MetricAliasService metricAliasService;
    
    /**
     * 从replace规则中提取SQL语句
     * @param replaceRules replace规则对象
     * @return 提取的SQL语句
     */
    private String extractSqlFromReplaceRules(Object replaceRules) {
        // 根据实际的replace规则结构来提取SQL语句
        // SQL语句存储在replace规则的"sql"字段中
        if (replaceRules instanceof Map<?, ?> rulesMap) {
            Object sqlObj = rulesMap.get("sql");
            if (sqlObj != null) {
                return sqlObj.toString();
            }
        }
        return "";
    }
    
    /**
     * 从replace规则中创建仅包含替换规则的Map，排除sql字段
     * @param replaceRules replace规则对象
     * @param originalSql 原始SQL语句
     * @return 仅包含替换规则的Map
     */
    private Map<String, String> createReplacementRules(Object replaceRules, String originalSql) {
        Map<String, String> replacementRules = new HashMap<>();
        if (replaceRules instanceof Map<?, ?> rulesMap) {
            for (Map.Entry<?, ?> entry : rulesMap.entrySet()) {
                // 排除sql字段，只保留替换规则
                if (!"sql".equals(entry.getKey()) && entry.getValue() != null) {
                    String fieldName = entry.getKey().toString();
                    String newValue = entry.getValue().toString();
                    
                    // 直接使用字段名作为键，新值作为值
                    replacementRules.put(fieldName, newValue);
                }
            }
        }
        return replacementRules;
    }

    /**
     * 从SQL语句中提取指定字段的值
     * @param sql SQL语句
     * @param fieldName 字段名
     * @return 字段值，如果未找到则返回null
     */
    private String extractFieldValueFromSql(String sql, String fieldName) {
        // 匹配格式：字段名 = '值' 或 字段名= '值' 或 字段名 ='值' 或 字段名 ='值'
        Pattern pattern = Pattern.compile(fieldName + "\\s*=\\s*'([^']*)'", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sql);

        // 查找匹配项，返回字段值
        if (matcher.find()) {
            String value = matcher.group(1);
            return value != null && !value.trim().isEmpty() ? value : null;
        }

        // 也检查不带引号的情况
        Pattern patternNoQuotes = Pattern.compile(fieldName + "\\s*=\\s*([^\\s]+)", Pattern.CASE_INSENSITIVE);
        Matcher matcherNoQuotes = patternNoQuotes.matcher(sql);
        if (matcherNoQuotes.find()) {
            String value = matcherNoQuotes.group(1);
            return value != null && !value.trim().isEmpty() ? value : null;
        }

        return null;
    }

    /**
     * Node 执行函数：
     * - 从状态中读取 replace 规则，其中包含SQL语句
     * - 调用 MetricAliasService 进行批量替换
     * - 将结果写回到 output
     */
    @Override
    public Map<String, Object> apply(OverAllState state) throws Exception {
        Map<String, Object> updated = new HashMap<>();
        try {
            // SQL语句现在包含在replace规则中，不再需要单独的input参数
            Object replaceRules = state.value(REPLACE, Object.class)
                    .orElse(null);

            // 从replace规则中提取SQL语句
            String inputSql = extractSqlFromReplaceRules(replaceRules);
            
            // 创建仅包含替换规则的Map，排除sql字段
            Map<String, String> replacementRules = createReplacementRules(replaceRules, inputSql);
            
            String outputSql = metricAliasService.applyReplacements(inputSql, replacementRules);
            updated.put(OUTPUT, outputSql);
        } catch (Exception e) {
            updated.put(OUTPUT, "");
            updated.put("error", e.getMessage());
        }
        return updated;
    }
}


